"use strict";


const _ 		= require("lodash");
const moment = require("moment");
const appRoot = require("app-root-path");
const {QueryTypes,Op,Transaction} = require("sequelize");
const PGMixin = require(appRoot + "/mixins/postgres.mixin");
const CacheCleanerMixin = require(appRoot + "/mixins/cache.cleaner.mixin");
const geofenceModel = require(appRoot + "/pgmodels/geofenceModel");

const { MoleculerClientError } = require("moleculer").Errors;



/**
 * @typedef {import('moleculer').Context} Context Moleculer's Context
 * 电子围栏的增、删、改、查，此处主要是地理空间数据类型的例子，需要数据库支持 gis ,即需要 post Gis
 */

module.exports = {
	name: "geofence",
	version: 1,
	/**
	 * Mixins
	 */
	mixins:[
		PGMixin("geofence"),
		CacheCleanerMixin([
			"cache.clean.geofence",
		])
	],
	model: geofenceModel,

	/**
	 * Settings
	 */
	settings: {
		auth: "ignore",
		tags: [ "Geofence" ],
		excludeDBService:["remove","create","update","get"],
	},


	/**
	 * Actions
	 */
	actions: {


		/**
		 * 根据电子围栏id,获取电子围栏信息
		 *
		 */
		getEntity:{
			timeout:0,
			rest:"GET /:id",
			summary:"检查电子围栏。",
			description:"根据电子围栏 id 获取对应的电子围栏信息。",
			params:{
				id:{ type:"number", convert:true, integer:true },
			},
			async handler(ctx) {
				return await this.adapter.model.findOne({
					where:{
						id:ctx.params.id,
					}
				});
			}
		},


		/**
		 * 创建电子围栏
		 *
		 * @returns {Object} Created entity
		 */
		createEntity: {
			rest: "POST /",
			summary: "新增电子围栏。",
			description: "根据电子围栏参数创建新电子围栏。",
			params:{
				geofenceName:{ type:"string",  max:200, optional:false, trim:true, description:"电子围栏名称",example:"东南一号围栏"},
				description:{ type:"string",  max:200, optional:true, trim:true, description:"电子围栏描述（备注）",example:"东南方向一号禁区"},
				type:{ type:"string", default:"polygon" ,description:"电子围栏形状，默认多边形 polygon，目前只支持简单多边形"},
				coordinates:{
					type:"array",
					items:{
						type:"array",
						items:{ type:"number", convert:true, integer:false, length:2 },
						optional:false
					},
					min:1,
					optional:false,
					description:"电子围栏边界（电子围栏的多边形定义）",
					example:[[0,0],[180,0],[180,90],[0,90]]
				},
				geofenceRule:{ type: "number", convert:true, integer:true, enum: [1, 2],default:1 , optional:true, description:"电子围栏规则，目前主要支持：1 进入电子围栏；2 离开电子围栏。",example:1},
			},
			async handler(ctx) {
				let entity = await this.createGeofenceBoundary(ctx.params);
				const doc  = await this.adapter.model.create(entity);
				const entityDb = await this.transformDocuments(ctx, {}, doc);
				await this.entityChanged("created", entityDb, ctx);
				return entityDb;
			}
		},

		/**
		 * 修改电子围栏
		 *
		 * @returns {Object} Updated entity
		 */
		updateEntity: {
			rest: "PUT /",
			summary: "修改电子围栏。",
			description: "根据电子围栏 id 修改电子围栏信息。",
			params: {
				id:{ type:"number", optional:false, convert:true, integer:true, min:1,description:"电子围栏 id" },
				geofenceName:{ type:"string",  max:200, optional:false, trim:true, description:"电子围栏名称",example:"东南一号围栏"},
				description:{ type:"string",  max:200, optional:true, trim:true, description:"电子围栏描述（备注）",example:"东南方向一号禁区"},
				type:{ type:"string", default:"polygon" ,description:"电子围栏形状，默认多边形 polygon，目前只支持简单多边形"},
				coordinates:{
					type:"array",
					items:{
						type:"array",
						items:{ type:"number", convert:true, integer:false, length:2 },
						optional:false
					},
					min:1,
					optional:false,
					description:"电子围栏边界（电子围栏的多边形定义）",
					example:[[0,0],[180,0],[180,90],[0,90]]
				},
				geofenceRule:{ type: "number", convert:true, integer:true, enum: [1, 2],default:1 , optional:true,description:"电子围栏规则，目前主要支持：1 进入电子围栏；2 离开电子围栏。",example:1},
			},
			async handler(ctx) {
				let entity = ctx.params;
				if (entity.id) {
					const found = await this.adapter.findById(Number(entity.id));
					if (!found){
						throw new MoleculerClientError("Geofence not found!", 404);
					}
				}
				entity = await this.createGeofenceBoundary(ctx.params);
				const update = {
					"$set": entity
				};
				const doc = await this.adapter.updateById(Number(entity.id), update);
				const entityDb = await this.transformDocuments(ctx, {}, doc);
				await this.entityChanged("updated", entityDb, ctx);
				return entityDb;
			}
		},


		/**
		 * 删除电子围栏
		 *
		 * @returns {Object} deleted entity
		 */
		deleteEntity: {
			summary: "删除电子围栏。",
			description: "根据电子围栏 id 删除电子围栏。",
			rest: "DELETE /:id",
			params:{
				id:{ type:"number",convert:true, integer:true, description:"电子围栏id" },
			},
			async handler(ctx) {
				let entity = await this.adapter.removeById(Number(ctx.params.id));
				if(!entity){
					throw new MoleculerClientError("Geofence not found!", 404);
				}
				await this.entityChanged("removed", entity, ctx);
				return entity;
			}
		},
	},

	/**
	 * Methods
	 */
	methods: {




		/**
		 * 根据边界点，创建电子围栏结构
		 * @param params
		 * @returns {geofenceBoundary}
		 */
		async createGeofenceBoundary(params) {
			if(params && params.coordinates && _.isArray(params.coordinates) && params.coordinates.length > 0){
				let lastIndex = params.coordinates.length -1;
				if(params.coordinates[0][0] !== params.coordinates[lastIndex][0] || params.coordinates[0][1] !== params.coordinates[lastIndex][1]){
					params.coordinates.push(params.coordinates[0]);
				}
			}
			let isSimplePolygon = await this.broker.call("v1.geofence.validatePolygon", {geom:params.coordinates}, { timeout:0 });
			if(!isSimplePolygon){
				throw new MoleculerClientError("Polygon is not a simple polygon.", 417);
			}
			params.geofenceBoundary = {
				type:params.type,
				coordinates:[params.coordinates]
			};
			delete params.type;
			delete params.coordinates;
			return params;
		},


	},

	/**
	 * Service created lifecycle event handler
	 */
	created() {

	},

	/**
	 * Service started lifecycle event handler
	 */
	async started() {

	},

	/**
	 * Service stopped lifecycle event handler
	 */
	async stopped() {

	},

	/**
	 * Fired after database connection establishing.
	 */
	async afterConnected() {

	}
};
